/**
 * Project Name:九色鹿
 * File Name:BaseController.java
 * Package Name:com.fxp.project.jiuselu.web.base.controller
 * Date:2021-08-29 12:53 下午
 * Copyright (c) 2021, Jason.Wang All Rights Reserved.
 */
package com.fxp.project.jiuselu.web.base.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fxp.project.jiuselu.commons.constant.ConstantCode;
import com.fxp.project.jiuselu.commons.exceptions.ParamException;
import com.fxp.project.jiuselu.commons.utils.CommonUtil;
import com.fxp.project.jiuselu.web.constant.Constants;
import com.fxp.project.jiuselu.web.domain.CommonResult;
import com.fxp.project.jiuselu.web.models.user.entity.JslUser;
import com.fxp.project.jiuselu.web.security.userdetails.CustomerUserDetails;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * ClassName: BaseController<br/>
 * Function: 基础控制器<br/>
 * Date: 2021-08-29 12:53 下午<br/>
 *
 * @author Jason.Wang
 * @version 1.0.0.0
 * @see
 * @since JDK 1.8
 */
public class BaseController {
    /**
     * 注入的请求对象
     */
    @Autowired
    protected HttpServletRequest request;
    /**
     * Redis操作类
     */
    @Autowired
    protected StringRedisTemplate stringRedisTemplate;
    @Autowired
    RedisTemplate<String, Object> objectRedisTemplate;
    /**
     * 短信验证码的有效时常
     */
    protected Integer smsOften = 3;
    /**
     * IM UserSign的有效时常
     */
    protected Integer imUserSignExpire = 6;

    /**
     * checkBindResult: check param valid result<br/>
     *
     * @param result
     * @author Jason.Wang
     * @createTime 2020/3/12 21:55
     */
    protected void checkBindResult(BindingResult result) {
        if (result.hasErrors()) {
            String errFieldStr = result.getAllErrors().stream()
                    .map(obj -> JSON.parseObject(JSON.toJSONString(obj)))
                    .map(err -> err.getString("field"))
                    .collect(Collectors.joining(","));
            StringUtils.removeEnd(errFieldStr, ",");
            String message = "these fields can not be empty:" + errFieldStr;
            throw new ParamException(ConstantCode.PARAM_EXCEPTION.getCode(), message);
        }
    }

    /**
     * getCurrentUserInfo: 获取当前用户的信息<br/>
     *
     * @return
     * @author Jason.Wang
     * @createTime 2020/3/15 11:45
     */
    protected JslUser getCurrentUserInfo() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication.getPrincipal().equals("anonymousUser"))
            throw new ParamException(ConstantCode.TOKEN_EXPIRE.getCode(),"请登录");
        CustomerUserDetails userDetails = (CustomerUserDetails) authentication.getPrincipal();
        if (null != userDetails && null != userDetails.getJslUser()) {
            return userDetails.getJslUser();
        }
        return null;
    }

    public static JslUser getUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication.getPrincipal().equals("anonymousUser"))
            throw new ParamException(ConstantCode.TOKEN_EXPIRE.getCode(),"请登录");
        CustomerUserDetails userDetails = (CustomerUserDetails) authentication.getPrincipal();
        if (null != userDetails && null != userDetails.getJslUser()) {
            return userDetails.getJslUser();
        }
        return null;
    }

    /**
     * setPageQueryTag: 配置当前分页查询的标识<br/>
     *
     * @param string
     * @param currentPage
     * @return
     * @author Jason.Wang
     * @createTime 2020/3/15 17:29
     */
    protected LocalDateTime setPageQueryTag(String string, Integer currentPage) {
        LocalDateTime currentTime = CommonUtil.getCurrentDateTime();
        String key = String.format(string, getCurrentUserInfo().getUserId());
        return getLocalDateTimeTag(currentPage, currentTime, key);
    }

    protected LocalDateTime setPageQueryTagWithOutLogin(String string, Integer currentPage) {
        LocalDateTime currentTime = CommonUtil.getCurrentDateTime();
        String key = String.format(string, "anonymous");
        return getLocalDateTimeTag(currentPage, currentTime, key);
    }

    /**
     * setPageQueryTag: 使用模版并配置对应的值获取当前分页<br/>
     *
     * @param key
     * @param currentPage
     * @param args
     * @return
     * @author Jason.Wang
     * @createTime 2020/3/29 22:30
     */
    protected LocalDateTime setPageQueryTagWithOutLogin(String key, Integer currentPage, Object... args) {
        LocalDateTime currentTime = CommonUtil.getCurrentDateTime();
        key = String.format(key, args);
        return getLocalDateTimeTag(currentPage, currentTime, key);
    }

    /**
     * getLongTag: 获取当前缓存的数据<br/>
     *
     * @param currentPage
     * @param currentTime
     * @param key
     * @return
     * @author Jason.Wang
     * @date 2021/8/29 1:00 下午
     */
    private LocalDateTime getLocalDateTimeTag(Integer currentPage, LocalDateTime currentTime, String key) {
        if (!currentPage.equals(1) && Boolean.TRUE.equals(objectRedisTemplate.hasKey(key))) {
            currentTime = (LocalDateTime) Objects.requireNonNull(objectRedisTemplate.opsForValue().get(key));
        }
        objectRedisTemplate.opsForValue().set(key, currentTime);
        objectRedisTemplate.expire(key, 30L, TimeUnit.MINUTES);
        return currentTime;
    }

    /**
     * setPageQueryTag: 使用模版并配置对应的值获取当前分页<br/>
     *
     * @param key
     * @param currentPage
     * @param args
     * @return
     * @author Jason.Wang
     * @createTime 2020/3/29 22:30
     */
    protected LocalDateTime setPageQueryTag(String key, Integer currentPage, Object... args) {
        LocalDateTime currentTime = CommonUtil.getCurrentDateTime();
        key = String.format(key, args);
        return getLocalDateTimeTag(currentPage, currentTime, key);
    }

    /**
     * setPageResult: 配置分页返回数据<br/>
     *
     * @param commonResult
     * @param pageInfo
     * @author Jason.Wang
     * @createTime 2020/3/15 17:39
     */
    protected void setPageResult(CommonResult<Map<String, Object>> commonResult, PageInfo<?> pageInfo) {
        Map<String, Object> map = new HashMap<>();
        map.put("count", null != pageInfo ? pageInfo.getTotal() : 0);
        map.put("list", null != pageInfo ? pageInfo.getList() : null);
        map.put("page", pageInfo.getPageNum());
        map.put("size", pageInfo.getSize());
        commonResult.setData(map);
    }

    /**
     * setMobileCode: 设置手机验证码<br/>
     *
     * @param mobile
     * @param code
     * @author Jason.Wang
     * @createTime 2020/4/1 23:50
     */
    protected void setMobileCode(String mobile, String code) {
        String key = String.format(Constants.USER_MOBILE_SMS_CODE, mobile);
        stringRedisTemplate.opsForValue().set(key, code);
        stringRedisTemplate.expire(key, smsOften, TimeUnit.MINUTES);
    }
//
//    /**
//     * getIMUserSign: 获取IM的UserSign<br/>
//     *
//     * @return
//     * @author Jason.Wang
//     * @createTime 2020/4/18 22:32
//     */
//    protected String getIMUserSign() {
//        UserInfo userInfo = getCurrentUserInfo();
//        String userSign = null;
//        if (null != userInfo) {
//            String key = String.format(Constants.USER_IM_USER_SIGN, generateUserSig.getType(), userInfo.getUserId());
//            if (stringRedisTemplate.hasKey(key)) {
//                userSign = stringRedisTemplate.opsForValue().get(key);
//            } else {
//                userSign = generateUserSig.genUserSig(userInfo.getUserId().toString());
//                stringRedisTemplate.opsForValue().set(key, userSign);
//                stringRedisTemplate.expire(key, imUserSignExpire, TimeUnit.DAYS);
//            }
//        }
//        return userSign;
//    }
//

    /**
     * getMobileCode: 获取验证码<br/>
     *
     * @param mobile
     * @return
     * @author Jason.Wang
     * @createTime 2020/4/1 23:53
     */
    protected String getMobileCode(String mobile) {
        String key = String.format(Constants.USER_MOBILE_SMS_CODE, mobile);
        if (stringRedisTemplate.hasKey(key)) {
            return stringRedisTemplate.opsForValue().get(key);
        }
        return "";
    }

    /**
     * validMobileCode: 验证手机和验证码是否正确<br/>
     *
     * @param mobile
     * @param code
     * @return
     * @author Jason.Wang
     * @createTime 2020/4/1 23:52
     */
    protected boolean validMobileCode(String mobile, String code) {
        return (StringUtils.isNotBlank(code) && code.equals(getMobileCode(mobile)));
    }

    /**
     * scan : Redis Scan的实现<br/>
     *
     * @param pattern  表达式
     * @param consumer 对迭代到的key进行操作
     * @author Jason
     * @date 2020-05-03 23:20
     */
    public void scan(String pattern, Consumer<byte[]> consumer) {
        //然后使用scan命令，不要使用keys see https://www.cnblogs.com/yangyang2018/p/10275671.html
//        scan(pattern, item -> {
//            //符合条件的key
//            String key = new String(item, StandardCharsets.UTF_8);
//            keys.add(key);
//        });
        stringRedisTemplate.execute((RedisConnection connection) -> {
            try (Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().count(Long.MAX_VALUE).match(pattern).build())) {
                cursor.forEachRemaining(consumer);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        });
    }

    /**
     * queryChatRedisData : 排序之后处理<br/>
     *
     * @param userId
     * @param key
     * @return
     * @author Jason
     * @date 2020-05-16 10:23
     */
    protected List<JSONObject> queryChatRedisData(Long userId, String key) {
        List<JSONObject> list = new ArrayList<>();
        Set<String> tempKeys = stringRedisTemplate.opsForZSet().reverseRange(key, 0, -1);
        if (!CollectionUtils.isEmpty(tempKeys)) {
            tempKeys.forEach(item -> {
                try {
                    JSONObject object = JSONObject.parseObject(stringRedisTemplate.opsForValue().get(String.format("im:chat:item:%s", item)));
                    if (null != object && !object.isEmpty()) {
                        //判断当前的用户是否将聊天置顶
                        String lockedKey = String.format("im:chat:user:%s:top:%s", userId, item);
                        if (stringRedisTemplate.hasKey(lockedKey) && "1".equals(stringRedisTemplate.opsForValue().get(lockedKey))) {
                            object.put("locked", 1);
                        } else {
                            object.put("locked", 0);
                        }
                        //判断当前个人用户的聊天内容是否存在
                        String content = stringRedisTemplate.opsForValue().get(String.format("im:chat:user:%s:content:%s", userId, item));
                        if (StringUtils.isNotBlank(content)) {
                            object.put("content", content);
                        }
                        list.add(object);
                    }
                } catch (Exception ex) {
                }
            });
            list.sort((a, b) -> {
                long obj1 = a.getLongValue("locked");
                long obj2 = b.getLongValue("locked");
                long diff = obj2 - obj1;
                if (diff > 0) {
                    return 1;
                } else if (diff < 0) {
                    return -1;
                }
                return 0; //相等为0
            });
        }
        return list;
    }

    /**
     * 发送内容。使用UTF-8编码。
     *
     * @param response
     * @param contentType
     * @param text
     */
    public static void render(HttpServletResponse response, String contentType, String text) {
        response.setContentType(contentType);
        response.setCharacterEncoding("utf-8");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        try {
            response.getWriter().write(text);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
